package main

import (
	"bufio"
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"sync"
)

type SocketClient struct {
	Close       bool
	Conn        net.Conn
	Num         int64 // 客户端发送消息次数
	ConnStr     string
	SocketType  int    // socket类型0为普通TCP socket 1为websocket  2为UDP  3为post 4为get
	LastRecvBuf []byte // 上次接受的内容
	Method      string //http请求的方式
	Url         string
	UrlPath     []string
	UrlParam    map[string]string
	Header      map[string]string
	Body        []byte
	UserID      string //用户ID
	UserType    string //用户类型：1为消费者，2为加盟商
	LoginTime   int64  //登录时间
	WeChat      string //微信ID
	UnionID     string //微信unionID
	IsGzip      bool
}

type SocketServer struct {
	name        string
	Clients     map[string]*SocketClient //所有客户端 IP:端口
	ClientsLock sync.RWMutex             //读写锁
	Xiaofeizhe  map[string]string        //所有消费者   用户ID    消费者IP:端口
	Jiameng     map[string]string        //所有加盟商   用户ID    监工IP:端口
	ServerPort  string
}

func (this *SocketServer) Init(name string, Listen string) {
	this.ServerPort = Listen
	this.name = name

	this.Clients = make(map[string]*SocketClient)
}

// isPotentialHTTP 快速判断是否为可能的HTTP请求
func (this *SocketServer) isPotentialHTTP(buf []byte) bool {
	methods := [][]byte{
		[]byte("GET"), []byte("POST"), []byte("HEAD"), []byte("OPTIONS"),
	}

	for _, m := range methods {
		if bytes.HasPrefix(buf, m) && len(buf) > len(m) && buf[len(m)] == ' ' {
			return true
		}
	}
	return false
}

// ParseHTTP 解析TCP字节流中的HTTP请求
// 输入: buf - 原始字节流(可能包含不完整或多条请求)
// 输出:
//
//	Shengyu []byte  - 未处理的剩余字节
//	Flag int   - -1的时候表示应立马断开tcp连接，1的时候表示是http，0的时候表示无法准确判断
//	Url string       - 请求路径(不含查询参数)
//	Params map[string]string - URL查询参数
//	Body []byte      - 请求体内容
func (this *SocketServer) ParseHTTP(buf []byte) (Method string, Shengyu []byte, Flag int, Url string, Params map[string]string, Body []byte) {
	// 快速失败：非HTTP请求直接返回原始数据
	if !this.isPotentialHTTP(buf) {
		return "", buf, -1, "", nil, nil
	}

	// 将字节流转换为可操作的Reader
	reader := bytes.NewReader(buf)

	// 读取第一行判断是否为HTTP请求
	req, err := http.ReadRequest(bufio.NewReader(reader))
	if err != nil || req.Method == "" {
		return "", buf, 0, "", nil, nil
	}

	// 解析URL和查询参数
	Url = req.URL.Path
	Params = make(map[string]string)

	for k, _ := range req.Header {
		Params[k] = req.Header.Get(k)
	}

	// 读取请求体
	bodyBuf := new(bytes.Buffer)
	if req.ContentLength > 0 {
		if _, err0 := bodyBuf.ReadFrom(req.Body); err0 == nil {
			Body = bodyBuf.Bytes()
		}
	}

	// 计算已处理数据长度
	processedLen := len(buf) - reader.Len()
	Shengyu = buf[processedLen:]
	return req.Method, Shengyu, 1, Url, Params, Body
}

func (this *SocketServer) connHandler(mystruct *SocketClient, conn net.Conn) {
	Flag := 0
	ReadBuf := make([]byte, 4096)
	for {
		//3.1 网络数据流读入 buffer
		cnt, err := conn.Read(ReadBuf)
		//3.2 数据读尽、读取错误 关闭 socket 连接
		if cnt == 0 || err != nil {
			this.Close(conn, mystruct)
			return
		}
		mystruct.Num += 1
		allbytes := BytesCombine(mystruct.LastRecvBuf, ReadBuf[0:cnt])
		mystruct.LastRecvBuf = make([]byte, 0)

		if mystruct.SocketType != 1 {
			// 解析HTTP请求
			mystruct.Method, mystruct.LastRecvBuf, Flag, mystruct.Url, mystruct.Header, mystruct.Body = this.ParseHTTP(allbytes)
			if Flag == -1 {
				this.Close(conn, mystruct)
				break
			}
			if Flag == 0 {
				continue
			}
		}
		if mystruct.Method == "GET" {
			mystruct.SocketType = 3
		}
		if mystruct.Method == "POST" {
			mystruct.SocketType = 4
		}
		if mystruct.SocketType == -1 {

			if mystruct.Header["Sec-Websocket-Key"] != "" {
				secWebsocketKey := strings.ReplaceAll(mystruct.Header["Sec-Websocket-Key"], " ", "")
				keyGUID := "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
				hasher := sha1.New()
				hasher.Write([]byte(secWebsocketKey + keyGUID))
				hash := hasher.Sum(nil)
				accept := make([]byte, base64.StdEncoding.EncodedLen(len(hash)))
				base64.StdEncoding.Encode(accept, hash)
				response := "HTTP/1.1 101 Switching Protocols\r\n"
				response += "Upgrade: websocket\r\n"
				response += "Connection: Upgrade\r\n"
				response += "Sec-WebSocket-Accept: " + string(accept) + "\r\n\r\n"
				conn.Write([]byte(response))
				mystruct.SocketType = 1
				continue
			}

		}
		if mystruct.Method == "OPTIONS" {
			strr := GMT()
			s := "HTTP/1.1 200 OK\r\nAllow: OPTIONS, GET, HEAD, POST\r\nAccess-Control-Allow-Origin:*\r\nConnection: keep-close\r\nCache-Control: max-age=604800\r\nDate:" + strr + "\r\nExpires" + strr + "\r\nServer: privateServer\r\nx-ec-custom-error: 0\r\nContent-Length:0"
			s = s + "\r\n\r\n"
			conn.Write([]byte(s))
			continue
		}
		if mystruct.SocketType == 1 {
			mystruct.Body, mystruct.LastRecvBuf = this.WebSocketParse(allbytes)
		}
		this.ToInterface(mystruct)
	}

}

// WebSocketParse 解析WebSocket协议帧并返回有效数据和剩余字节
// 输入参数: input - 原始字节流(包含可能的一个或多个帧)
// 返回值: data - 当前解析出的有效载荷数据
//
//	shengyu - 未能处理的剩余字节
func (this *SocketServer) WebSocketParse(input []byte) (data []byte, shengyu []byte) {
	// 基础头校验（至少需要2字节）
	if len(input) < 2 {
		return []byte{}, input
	}

	// 解析基础头信息
	maskBit := input[1] >> 7           // 掩码标识位
	payloadLen := int(input[1] & 0x7F) // 初始有效载荷长度
	headerSize := 2                    // 基础头长度

	// 处理扩展长度字段
	switch payloadLen {
	case 126:
		headerSize += 2
		if len(input) < headerSize {
			return []byte{}, input
		}
		payloadLen = int(binary.BigEndian.Uint16(input[2:4]))
	case 127:
		headerSize += 8
		if len(input) < headerSize {
			return nil, input
		}
		payloadLen = int(binary.BigEndian.Uint64(input[2:10]))
	}

	// 处理掩码字段
	if maskBit == 1 {
		headerSize += 4 // 增加掩码密钥长度
		if len(input) < headerSize {
			return []byte{}, input
		}
	}

	// 检查完整数据长度
	totalSize := headerSize + payloadLen
	if len(input) < totalSize {
		return []byte{}, input
	}

	// 提取有效载荷数据
	payload := input[headerSize:totalSize]

	// 执行掩码解码（如果存在）
	if maskBit == 1 {
		maskKey := input[headerSize-4 : headerSize]
		for i := 0; i < len(payload); i++ {
			payload[i] ^= maskKey[i%4]
		}
	}

	return payload, input[totalSize:]
}
func (this *SocketServer) Close(conn net.Conn, mystruct *SocketClient) {
	this.ClientsLock.Lock()
	delete(this.Clients, mystruct.ConnStr)
	conn.Close()
	mystruct.Close = true
	this.ClientsLock.Unlock()
}

// ToInterface 处理接收到的接口消息
func (this *SocketServer) ToInterface(mystruct *SocketClient) {
	//fmt.Println("kehuduan", mystruct.SocketType, mystruct.Url, mystruct.Header, string(mystruct.Body))
	if strings.Replace(mystruct.Header["Accept-Encoding"], "gzip", "", 1) != mystruct.Header["Accept-Encoding"] {
		mystruct.IsGzip = true
	}

	APIName := ""
	mystruct.UrlPath = []string{}
	mystruct.UrlParam = map[string]string{}
	if mystruct.SocketType == 3 || mystruct.SocketType == 4 {

		_, mystruct.UrlPath, mystruct.UrlParam, _ = ParseUrlNoCheck(mystruct.Url)
		if len(mystruct.UrlPath) > 0 {
			APIName = mystruct.UrlPath[0]
		} else {
			Response(mystruct, -1, "路径错误", "", map[string]string{})
			return
		}
	}
	if mystruct.SocketType == 1 {
		APIName = "APIWebsocket"
	}

	pp := reflect.ValueOf(Imp) // 取得struct变量的指针
	f := pp.MethodByName(APIName)
	if !f.IsValid() {
		Response(mystruct, -2, "接口不存在", "", map[string]string{})
		return
	}
	paramList := []reflect.Value{reflect.ValueOf(mystruct)}
	f.Call(paramList)
}

// WebSocketSendData 给客户端发送数据
func WebSocketSendData(data []byte) []byte {
	lenth := len(data)
	token := string(0x81)
	if lenth < 126 {
		token += string(lenth)
	}
	bb, _ := IntToBytes(0x81, 1)
	b0 := bb[0]
	b1 := byte(0)
	framePos := 0
	switch {
	case lenth >= 65536:
		writeBuf := make([]byte, 10)
		writeBuf[framePos] = b0
		writeBuf[framePos+1] = b1 | 127
		binary.BigEndian.PutUint64(writeBuf[framePos+2:], uint64(lenth))

		return BytesCombine(writeBuf, data)
	case lenth > 125:
		writeBuf := make([]byte, 4)
		writeBuf[framePos] = b0
		writeBuf[framePos+1] = b1 | 126
		binary.BigEndian.PutUint16(writeBuf[framePos+2:], uint16(lenth))
		return BytesCombine(writeBuf, data)
	default:
		writeBuf := make([]byte, 2)
		writeBuf[framePos] = b0
		writeBuf[framePos+1] = b1 | byte(lenth)

		return BytesCombine(writeBuf, data)
	}
	return []byte("")
}

type ReturnMsgOtherData struct {
	ErrorCode int         `json:"errorCode"`
	Error     string      `json:"error"`
	Data      interface{} `json:"data"`
}

func Response(mystruct *SocketClient, ErrorCode int, Error string, Data interface{}, Header map[string]string) {
	//1. 处理返回数据格式
	res := ReturnMsgOtherData{}
	res.ErrorCode = ErrorCode
	res.Error = Error
	if Data == "" {
		res.Data = make(map[string]interface{})
	} else {
		res.Data = Data
	}
	jsonData, _ := json.Marshal(res)
	//2. 如果是websocket，直接返回
	if mystruct.SocketType == 1 {
		_, e := mystruct.Conn.Write(WebSocketSendData(jsonData))
		if e != nil {
			mystruct.Close = true
		}
	}
	//3. 如果是http，处理header
	Header__ := map[string]string{
		"Content-Type":                     "application/json; charset=utf-8",
		"Access-Control-Allow-Origin":      "*",
		"Access-Control-Allow-Headers":     "*",
		"Access-Control-Allow-Methods":     "OPTIONS, GET, HEAD, POST",
		"Access-Control-Allow-Credentials": "true",
		"Connection":                       "keep-alive",
		"Allow":                            "OPTIONS, GET, HEAD, POST",
		"Date":                             GMT(),
	}
	//4. 合并header
	for k, v := range Header {
		Header__[k] = v
	}
	//5. 如果是gzip，处理header
	if mystruct.IsGzip == true {
		Header__["Content-Encoding"] = "gzip"
		Header__["Content-Type"] = "application/json;charset=utf-8"

		f, f0 := GzipStrNoBase64(jsonData)
		if f0 == true {
			jsonData = f
		}
	}
	Header__["Content-Length"] = strconv.Itoa(len(jsonData))
	//6. 生成最终数据
	Msg := "HTTP/1.1 200 OK\r\n"
	for k, v := range Header__ {
		Msg += k + ":" + v + "\r\n"
	}
	Msg += "\r\n" + string(jsonData)
	//7.发送数据
	_, e := mystruct.Conn.Write([]byte(Msg))
	if e != nil {
		mystruct.Close = true
	}

}

// Run 开启serverSocket
func (this *SocketServer) Run() {
	//1.监听端口
	TCPServer, err := net.Listen("tcp", this.ServerPort)
	if err != nil {
		Log("开启"+this.name+"失败，端口号", this.ServerPort, err)
		return
	}
	Log("开启"+this.name+"成功，端口号", this.ServerPort)

	for {
		conn, err01 := TCPServer.Accept()
		if err01 != nil {
			fmt.Println("连接出错")
			continue
		}
		this.ClientsLock.RLock()
		mystruct, ok := this.Clients[conn.RemoteAddr().String()]
		this.ClientsLock.RUnlock()
		if ok == false {
			this.ClientsLock.Lock()
			mystruct = new(SocketClient)
			mystruct.Conn = conn
			mystruct.ConnStr = conn.RemoteAddr().String()
			mystruct.SocketType = -1
			mystruct.Num = 0
			mystruct.Close = false
			mystruct.LastRecvBuf = make([]byte, 0)
			mystruct.Method = ""
			mystruct.Url = ""
			mystruct.Header = map[string]string{}
			mystruct.Body = []byte{}

			this.Clients[mystruct.ConnStr] = mystruct
			this.ClientsLock.Unlock()
		}
		//并发模式 接收来自客户端的连接请求，一个连接 建立一个 conn，服务器资源有可能耗尽 BIO模式
		go this.connHandler(mystruct, conn)
	}
}
